package com.powernode.service.impl;

import com.powernode.constant.Constants;
import com.powernode.service.LuaService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * Lua脚本服务实现类
 * 负责执行秒杀业务的核心Lua脚本，通过Redis实现分布式环境下的并发控制
 * 主要功能包括限流、防重复抢购和库存扣减的原子性操作
 */
@Component
public class LuaServiceImpl implements LuaService {
    // 定义Redis脚本对象，泛型指定为Long表示脚本返回值类型
    private DefaultRedisScript<Long> redisScript;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * Spring容器初始化后执行的方法
     * 用于加载Lua脚本并配置脚本返回值类型
     * @PostConstruct注解确保该方法在依赖注入完成后自动调用
     */
    @PostConstruct
    public void init() {
        redisScript = new DefaultRedisScript<>();
        // 设置Lua脚本返回值类型为Long
        redisScript.setResultType(Long.class);
        // 从类路径加载秒杀业务的Lua脚本文件
        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("seckill.lua")));
    }

    /**
     * 执行秒杀业务的Lua脚本
     * 通过Redis实现限流、防重复购买和库存扣减的原子性操作
     * @param id 商品ID
     * @param userId 用户ID
     * @return 执行结果：0-秒杀成功，1-库存不足，2-用户重复秒杀，3-限流
     */
    public long runLuaScript(Integer id, String userId) {
        // 限流key，格式为当前时间戳（秒级），用于实现每秒限流
        String limitKey = System.currentTimeMillis() / 1000 + "";//单位 秒

        // 用户购买标记key，格式为Constants.REDIS_HOLD + 商品ID + 用户ID
        // 用于防止同一用户重复购买同一商品
        String holdKey = Constants.REDIS_HOLD + id + ":" + userId;

        // 库存key，格式为Constants.REDIS_STORE + 商品ID
        // 用于存储和扣减商品库存
        String storeKey = Constants.REDIS_STORE + id;

        // 将所有Redis key封装为List集合，传递给Lua脚本
        List<String> keylist = Arrays.asList(limitKey, holdKey, storeKey);

        // 执行Lua脚本，参数说明：
        // redisScript - 预加载的Lua脚本对象
        // keylist - Redis key列表
        // userId - 第一个脚本参数（用户ID）
        // String.valueOf(Constants.MAX_LIMIT) - 第二个脚本参数（最大限流数）
        Long result = stringRedisTemplate.execute(redisScript, keylist, userId, String.valueOf(Constants.MAX_LIMIT));

        return result;
    }
}
